@@ -2,16 +2,19 @@ module LiquidInterpolatable |
||
| 2 | 2 |
extend ActiveSupport::Concern |
| 3 | 3 |
|
| 4 | 4 |
def interpolate_options(options, payload) |
| 5 |
- duped_options = options.dup.tap do |duped_options| |
|
| 6 |
- duped_options.each_pair do |key, value| |
|
| 7 |
- if value.class == String |
|
| 8 |
- duped_options[key] = Liquid::Template.parse(value).render(payload) |
|
| 9 |
- else |
|
| 10 |
- duped_options[key] = value |
|
| 11 |
- end |
|
| 5 |
+ case options.class.to_s |
|
| 6 |
+ when 'String' |
|
| 7 |
+ Liquid::Template.parse(options).render(payload) |
|
| 8 |
+ when 'ActiveSupport::HashWithIndifferentAccess', 'Hash' |
|
| 9 |
+ duped_options = options.dup |
|
| 10 |
+ duped_options.each do |key, value| |
|
| 11 |
+ duped_options[key] = interpolate_options(value, payload) |
|
| 12 |
+ end |
|
| 13 |
+ when 'Array' |
|
| 14 |
+ options.collect do |value| |
|
| 15 |
+ interpolate_options(value, payload) |
|
| 12 | 16 |
end |
| 13 | 17 |
end |
| 14 |
- duped_options |
|
| 15 | 18 |
end |
| 16 | 19 |
|
| 17 | 20 |
def interpolate_string(string, payload) |
@@ -2,6 +2,8 @@ require 'rturk' |
||
| 2 | 2 |
|
| 3 | 3 |
module Agents |
| 4 | 4 |
class HumanTaskAgent < Agent |
| 5 |
+ include LiquidInterpolatable |
|
| 6 |
+ |
|
| 5 | 7 |
default_schedule "every_10m" |
| 6 | 8 |
|
| 7 | 9 |
description <<-MD |
@@ -16,7 +18,7 @@ module Agents |
||
| 16 | 18 |
|
| 17 | 19 |
# Example |
| 18 | 20 |
|
| 19 |
- If created with an event, all HIT fields can contain interpolated values via [JSONPaths](http://goessner.net/articles/JsonPath/) placed between < and > characters. |
|
| 21 |
+ If created with an event, all HIT fields can contain interpolated values via [liquid templating](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid). |
|
| 20 | 22 |
For example, if the incoming event was a Twitter event, you could make a HITT to rate its sentiment like this: |
| 21 | 23 |
|
| 22 | 24 |
{
|
@@ -25,7 +27,7 @@ module Agents |
||
| 25 | 27 |
"hit": {
|
| 26 | 28 |
"assignments": 1, |
| 27 | 29 |
"title": "Sentiment evaluation", |
| 28 |
- "description": "Please rate the sentiment of this message: '<$.message>'", |
|
| 30 |
+ "description": "Please rate the sentiment of this message: '{{message}}'",
|
|
| 29 | 31 |
"reward": 0.05, |
| 30 | 32 |
"lifetime_in_seconds": "3600", |
| 31 | 33 |
"questions": [ |
@@ -83,7 +85,7 @@ module Agents |
||
| 83 | 85 |
"title": "Take a poll about some jokes", |
| 84 | 86 |
"instructions": "Please rank these jokes from most funny (5) to least funny (1)", |
| 85 | 87 |
"assignments": 3, |
| 86 |
- "row_template": "<$.joke>" |
|
| 88 |
+ "row_template": "{{joke}}"
|
|
| 87 | 89 |
}, |
| 88 | 90 |
"hit": {
|
| 89 | 91 |
"assignments": 5, |
@@ -168,7 +170,7 @@ module Agents |
||
| 168 | 170 |
{
|
| 169 | 171 |
'assignments' => 1, |
| 170 | 172 |
'title' => "Sentiment evaluation", |
| 171 |
- 'description' => "Please rate the sentiment of this message: '<$.message>'", |
|
| 173 |
+ 'description' => "Please rate the sentiment of this message: '{{message}}'",
|
|
| 172 | 174 |
'reward' => 0.05, |
| 173 | 175 |
'lifetime_in_seconds' => 24 * 60 * 60, |
| 174 | 176 |
'questions' => |
@@ -332,7 +334,7 @@ module Agents |
||
| 332 | 334 |
'name' => "Item #{index + 1}",
|
| 333 | 335 |
'key' => index, |
| 334 | 336 |
'required' => "true", |
| 335 |
- 'question' => Utils.interpolate_jsonpaths(options['poll_options']['row_template'], assignments[index].answers), |
|
| 337 |
+ 'question' => interpolate_string(options['poll_options']['row_template'], assignments[index].answers), |
|
| 336 | 338 |
'selections' => selections |
| 337 | 339 |
} |
| 338 | 340 |
end |
@@ -387,9 +389,9 @@ module Agents |
||
| 387 | 389 |
|
| 388 | 390 |
def create_hit(opts = {})
|
| 389 | 391 |
payload = opts['payload'] || {}
|
| 390 |
- title = Utils.interpolate_jsonpaths(opts['title'], payload).strip |
|
| 391 |
- description = Utils.interpolate_jsonpaths(opts['description'], payload).strip |
|
| 392 |
- questions = Utils.recursively_interpolate_jsonpaths(opts['questions'], payload) |
|
| 392 |
+ title = interpolate_string(opts['title'], payload).strip |
|
| 393 |
+ description = interpolate_string(opts['description'], payload).strip |
|
| 394 |
+ questions = interpolate_options(opts['questions'], payload) |
|
| 393 | 395 |
hit = RTurk::Hit.create(:title => title) do |hit| |
| 394 | 396 |
hit.max_assignments = (opts['assignments'] || 1).to_i |
| 395 | 397 |
hit.description = description |
@@ -2,10 +2,12 @@ require 'pp' |
||
| 2 | 2 |
|
| 3 | 3 |
module Agents |
| 4 | 4 |
class PeakDetectorAgent < Agent |
| 5 |
+ include LiquidInterpolatable |
|
| 6 |
+ |
|
| 5 | 7 |
cannot_be_scheduled! |
| 6 | 8 |
|
| 7 | 9 |
description <<-MD |
| 8 |
- Use a PeakDetectorAgent to watch for peaks in an event stream. When a peak is detected, the resulting Event will have a payload message of `message`. You can include extractions in the message, for example: `I saw a bar of: <foo.bar>` |
|
| 10 |
+ Use a PeakDetectorAgent to watch for peaks in an event stream. When a peak is detected, the resulting Event will have a payload message of `message`. You can include extractions in the message, for example: `I saw a bar of: {{foo.bar}}`, have a look at the [Wiki](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) for details.
|
|
| 9 | 11 |
|
| 10 | 12 |
The `value_path` value is a [JSONPaths](http://goessner.net/articles/JsonPath/) to the value of interest. `group_by_path` is a hash path that will be used to group values, if present. |
| 11 | 13 |
|
@@ -67,7 +69,7 @@ module Agents |
||
| 67 | 69 |
if newest_value > average_value + std_multiple * standard_deviation |
| 68 | 70 |
memory['peaks'][group] << newest_time |
| 69 | 71 |
memory['peaks'][group].reject! { |p| p <= newest_time - window_duration }
|
| 70 |
- create_event :payload => { 'message' => options['message'], 'peak' => newest_value, 'peak_time' => newest_time, 'grouped_by' => group.to_s }
|
|
| 72 |
+ create_event :payload => { 'message' => interpolate_string(options['message'], event.payload), 'peak' => newest_value, 'peak_time' => newest_time, 'grouped_by' => group.to_s }
|
|
| 71 | 73 |
end |
| 72 | 74 |
end |
| 73 | 75 |
end |
@@ -1,5 +1,7 @@ |
||
| 1 | 1 |
module Agents |
| 2 | 2 |
class TriggerAgent < Agent |
| 3 |
+ include LiquidInterpolatable |
|
| 4 |
+ |
|
| 3 | 5 |
cannot_be_scheduled! |
| 4 | 6 |
|
| 5 | 7 |
VALID_COMPARISON_TYPES = %w[regex !regex field<value field<=value field==value field!=value field>=value field>value] |
@@ -13,7 +15,7 @@ module Agents |
||
| 13 | 15 |
|
| 14 | 16 |
The `value` can be a single value or an array of values. In the case of an array, if one or more values match then the rule matches. |
| 15 | 17 |
|
| 16 |
- All rules must match for the Agent to match. The resulting Event will have a payload message of `message`. You can include extractions in the message, for example: `I saw a bar of: <foo.bar>` |
|
| 18 |
+ All rules must match for the Agent to match. The resulting Event will have a payload message of `message`. You can use liquid templating in the `message, have a look at the [Wiki](https://github.com/cantino/huginn/wiki/Formatting-Events-using-Liquid) for details. |
|
| 17 | 19 |
|
| 18 | 20 |
Set `keep_event` to `true` if you'd like to re-emit the incoming event, optionally merged with 'message' when provided. |
| 19 | 21 |
|
@@ -46,7 +48,7 @@ module Agents |
||
| 46 | 48 |
'value' => "foo\\d+bar", |
| 47 | 49 |
'path' => "topkey.subkey.subkey.goal", |
| 48 | 50 |
}], |
| 49 |
- 'message' => "Looks like your pattern matched in '<value>'!" |
|
| 51 |
+ 'message' => "Looks like your pattern matched in '{{value}}'!"
|
|
| 50 | 52 |
} |
| 51 | 53 |
end |
| 52 | 54 |
|
@@ -88,9 +90,9 @@ module Agents |
||
| 88 | 90 |
if match |
| 89 | 91 |
if keep_event? |
| 90 | 92 |
payload = event.payload.dup |
| 91 |
- payload['message'] = make_message(event[:payload]) if options['message'].present? |
|
| 93 |
+ payload['message'] = interpolate_string(options['message'], event.payload) if options['message'].present? |
|
| 92 | 94 |
else |
| 93 |
- payload = { 'message' => make_message(event[:payload]) }
|
|
| 95 |
+ payload = { 'message' => interpolate_string(options['message'], event.payload) }
|
|
| 94 | 96 |
end |
| 95 | 97 |
|
| 96 | 98 |
create_event :payload => payload |
@@ -1,15 +0,0 @@ |
||
| 1 |
-class MigrateHipchatAndEfAgentToLiquid < ActiveRecord::Migration |
|
| 2 |
- def up |
|
| 3 |
- Agent.where(:type => 'Agents::HipchatAgent').each do |agent| |
|
| 4 |
- LiquidMigrator.convert_all_agent_options(agent) |
|
| 5 |
- end |
|
| 6 |
- Agent.where(:type => 'Agents::EventFormattingAgent').each do |agent| |
|
| 7 |
- agent.options['instructions'] = LiquidMigrator.convert_hash(agent.options['instructions'], {:merge_path_attributes => true, :leading_dollarsign_is_jsonpath => true})
|
|
| 8 |
- agent.save |
|
| 9 |
- end |
|
| 10 |
- end |
|
| 11 |
- |
|
| 12 |
- def down |
|
| 13 |
- raise ActiveRecord::IrreversibleMigration, "Cannot revert migration to Liquid templating" |
|
| 14 |
- end |
|
| 15 |
-end |
@@ -1,11 +0,0 @@ |
||
| 1 |
-class MigratePushbulletAgentToLiquid < ActiveRecord::Migration |
|
| 2 |
- def up |
|
| 3 |
- Agent.where(:type => 'Agents::PushbulletAgent').each do |agent| |
|
| 4 |
- LiquidMigrator.convert_all_agent_options(agent) |
|
| 5 |
- end |
|
| 6 |
- end |
|
| 7 |
- |
|
| 8 |
- def down |
|
| 9 |
- raise ActiveRecord::IrreversibleMigration, "Cannot revert migration to Liquid templating" |
|
| 10 |
- end |
|
| 11 |
-end |
@@ -1,11 +0,0 @@ |
||
| 1 |
-class MigrateJabberAgentToLiquid < ActiveRecord::Migration |
|
| 2 |
- def up |
|
| 3 |
- Agent.where(:type => 'Agents::JabberAgent').each do |agent| |
|
| 4 |
- LiquidMigrator.convert_all_agent_options(agent) |
|
| 5 |
- end |
|
| 6 |
- end |
|
| 7 |
- |
|
| 8 |
- def down |
|
| 9 |
- raise ActiveRecord::IrreversibleMigration, "Cannot revert migration to Liquid templating" |
|
| 10 |
- end |
|
| 11 |
-end |
@@ -1,11 +0,0 @@ |
||
| 1 |
-class MigrateDataOutputAgentToLiquid < ActiveRecord::Migration |
|
| 2 |
- def up |
|
| 3 |
- Agent.where(:type => 'Agents::DataOutputAgent').each do |agent| |
|
| 4 |
- LiquidMigrator.convert_all_agent_options(agent) |
|
| 5 |
- end |
|
| 6 |
- end |
|
| 7 |
- |
|
| 8 |
- def down |
|
| 9 |
- raise ActiveRecord::IrreversibleMigration, "Cannot revert migration to Liquid templating" |
|
| 10 |
- end |
|
| 11 |
-end |
@@ -1,12 +0,0 @@ |
||
| 1 |
-class MigrateTranslationAgentToLiquid < ActiveRecord::Migration |
|
| 2 |
- def up |
|
| 3 |
- Agent.where(:type => 'Agents::TranslationAgent').each do |agent| |
|
| 4 |
- agent.options['content'] = LiquidMigrator.convert_hash(agent.options['content'], {:merge_path_attributes => true, :leading_dollarsign_is_jsonpath => true})
|
|
| 5 |
- agent.save |
|
| 6 |
- end |
|
| 7 |
- end |
|
| 8 |
- |
|
| 9 |
- def down |
|
| 10 |
- raise ActiveRecord::IrreversibleMigration, "Cannot revert migration to Liquid templating" |
|
| 11 |
- end |
|
| 12 |
-end |
@@ -1,14 +0,0 @@ |
||
| 1 |
-class MigrateTwitterPublishAgentToLiquid < ActiveRecord::Migration |
|
| 2 |
- def up |
|
| 3 |
- Agent.where(:type => 'Agents::TwitterPublishAgent').each do |agent| |
|
| 4 |
- if (message = agent.options.delete('message_path')).present?
|
|
| 5 |
- agent.options['message'] = "{{#{message}}}"
|
|
| 6 |
- agent.save |
|
| 7 |
- end |
|
| 8 |
- end |
|
| 9 |
- end |
|
| 10 |
- |
|
| 11 |
- def down |
|
| 12 |
- raise ActiveRecord::IrreversibleMigration, "Cannot revert migration to Liquid templating" |
|
| 13 |
- end |
|
| 14 |
-end |
@@ -0,0 +1,45 @@ |
||
| 1 |
+class MigrateAgentsToLiquidTemplating < ActiveRecord::Migration |
|
| 2 |
+ def up |
|
| 3 |
+ Agent.where(:type => 'Agents::HipchatAgent').each do |agent| |
|
| 4 |
+ LiquidMigrator.convert_all_agent_options(agent) |
|
| 5 |
+ end |
|
| 6 |
+ Agent.where(:type => 'Agents::EventFormattingAgent').each do |agent| |
|
| 7 |
+ agent.options['instructions'] = LiquidMigrator.convert_hash(agent.options['instructions'], {:merge_path_attributes => true, :leading_dollarsign_is_jsonpath => true})
|
|
| 8 |
+ agent.save |
|
| 9 |
+ end |
|
| 10 |
+ Agent.where(:type => 'Agents::PushbulletAgent').each do |agent| |
|
| 11 |
+ LiquidMigrator.convert_all_agent_options(agent) |
|
| 12 |
+ end |
|
| 13 |
+ Agent.where(:type => 'Agents::JabberAgent').each do |agent| |
|
| 14 |
+ LiquidMigrator.convert_all_agent_options(agent) |
|
| 15 |
+ end |
|
| 16 |
+ Agent.where(:type => 'Agents::DataOutputAgent').each do |agent| |
|
| 17 |
+ LiquidMigrator.convert_all_agent_options(agent) |
|
| 18 |
+ end |
|
| 19 |
+ Agent.where(:type => 'Agents::TranslationAgent').each do |agent| |
|
| 20 |
+ agent.options['content'] = LiquidMigrator.convert_hash(agent.options['content'], {:merge_path_attributes => true, :leading_dollarsign_is_jsonpath => true})
|
|
| 21 |
+ agent.save |
|
| 22 |
+ end |
|
| 23 |
+ Agent.where(:type => 'Agents::TwitterPublishAgent').each do |agent| |
|
| 24 |
+ if (message = agent.options.delete('message_path')).present?
|
|
| 25 |
+ agent.options['message'] = "{{#{message}}}"
|
|
| 26 |
+ agent.save |
|
| 27 |
+ end |
|
| 28 |
+ end |
|
| 29 |
+ Agent.where(:type => 'Agents::TriggerAgent').each do |agent| |
|
| 30 |
+ agent.options['message'] = LiquidMigrator.convert_make_message(agent.options['message']) |
|
| 31 |
+ agent.save |
|
| 32 |
+ end |
|
| 33 |
+ Agent.where(:type => 'Agents::PeakDetectorAgent').each do |agent| |
|
| 34 |
+ agent.options['message'] = LiquidMigrator.convert_make_message(agent.options['message']) |
|
| 35 |
+ agent.save |
|
| 36 |
+ end |
|
| 37 |
+ Agent.where(:type => 'Agents::HumanTaskAgent').each do |agent| |
|
| 38 |
+ LiquidMigrator.convert_all_agent_options(agent) |
|
| 39 |
+ end |
|
| 40 |
+ end |
|
| 41 |
+ |
|
| 42 |
+ def down |
|
| 43 |
+ raise ActiveRecord::IrreversibleMigration, "Cannot revert migration to Liquid templating" |
|
| 44 |
+ end |
|
| 45 |
+end |
@@ -22,7 +22,13 @@ module LiquidMigrator |
||
| 22 | 22 |
when 'ActiveSupport::HashWithIndifferentAccess' |
| 23 | 23 |
hash[key] = convert_hash(hash[key], options) |
| 24 | 24 |
when 'Array' |
| 25 |
- hash[key] = hash[key].collect { |k| convert_string(k, options[:leading_dollarsign_is_jsonpath])}
|
|
| 25 |
+ hash[key] = hash[key].collect { |k|
|
|
| 26 |
+ if k.class == String |
|
| 27 |
+ convert_string(k, options[:leading_dollarsign_is_jsonpath]) |
|
| 28 |
+ else |
|
| 29 |
+ convert_hash(k, options) |
|
| 30 |
+ end |
|
| 31 |
+ } |
|
| 26 | 32 |
end |
| 27 | 33 |
end |
| 28 | 34 |
# remove the unneeded *_path attributes |
@@ -50,6 +56,10 @@ module LiquidMigrator |
||
| 50 | 56 |
end |
| 51 | 57 |
end |
| 52 | 58 |
|
| 59 |
+ def self.convert_make_message(string) |
|
| 60 |
+ string.gsub(/<([^>]+)>/, "{{\\1}}")
|
|
| 61 |
+ end |
|
| 62 |
+ |
|
| 53 | 63 |
def self.convert_json_path(string, filter = "") |
| 54 | 64 |
check_path(string) |
| 55 | 65 |
if string.start_with? '$.' |
@@ -56,6 +56,14 @@ describe LiquidMigrator do |
||
| 56 | 56 |
end |
| 57 | 57 |
end |
| 58 | 58 |
|
| 59 |
+ describe "migrating the 'make_message' format" do |
|
| 60 |
+ it "should work" do |
|
| 61 |
+ LiquidMigrator.convert_make_message('<message>').should == '{{message}}'
|
|
| 62 |
+ LiquidMigrator.convert_make_message('<new.message>').should == '{{new.message}}'
|
|
| 63 |
+ LiquidMigrator.convert_make_message('Hello <world>. How is <nested.life>').should == 'Hello {{world}}. How is {{nested.life}}'
|
|
| 64 |
+ end |
|
| 65 |
+ end |
|
| 66 |
+ |
|
| 59 | 67 |
describe "migrating an actual agent" do |
| 60 | 68 |
before do |
| 61 | 69 |
valid_params = {
|
@@ -99,5 +107,50 @@ describe LiquidMigrator do |
||
| 99 | 107 |
expect { LiquidMigrator.convert_all_agent_options(@agent) }.
|
| 100 | 108 |
to raise_error("JSONPath '$.very.complex[*]' is too complex, please check your migration.")
|
| 101 | 109 |
end |
| 110 |
+ |
|
| 111 |
+ it "should work with the human task agent" do |
|
| 112 |
+ valid_params = {
|
|
| 113 |
+ 'expected_receive_period_in_days' => 2, |
|
| 114 |
+ 'trigger_on' => "event", |
|
| 115 |
+ 'hit' => |
|
| 116 |
+ {
|
|
| 117 |
+ 'assignments' => 1, |
|
| 118 |
+ 'title' => "Sentiment evaluation", |
|
| 119 |
+ 'description' => "Please rate the sentiment of this message: '<$.message>'", |
|
| 120 |
+ 'reward' => 0.05, |
|
| 121 |
+ 'lifetime_in_seconds' => 24 * 60 * 60, |
|
| 122 |
+ 'questions' => |
|
| 123 |
+ [ |
|
| 124 |
+ {
|
|
| 125 |
+ 'type' => "selection", |
|
| 126 |
+ 'key' => "sentiment", |
|
| 127 |
+ 'name' => "Sentiment", |
|
| 128 |
+ 'required' => "true", |
|
| 129 |
+ 'question' => "Please select the best sentiment value:", |
|
| 130 |
+ 'selections' => |
|
| 131 |
+ [ |
|
| 132 |
+ { 'key' => "happy", 'text' => "Happy" },
|
|
| 133 |
+ { 'key' => "sad", 'text' => "Sad" },
|
|
| 134 |
+ { 'key' => "neutral", 'text' => "Neutral" }
|
|
| 135 |
+ ] |
|
| 136 |
+ }, |
|
| 137 |
+ {
|
|
| 138 |
+ 'type' => "free_text", |
|
| 139 |
+ 'key' => "feedback", |
|
| 140 |
+ 'name' => "Have any feedback for us?", |
|
| 141 |
+ 'required' => "false", |
|
| 142 |
+ 'question' => "Feedback", |
|
| 143 |
+ 'default' => "Type here...", |
|
| 144 |
+ 'min_length' => "2", |
|
| 145 |
+ 'max_length' => "2000" |
|
| 146 |
+ } |
|
| 147 |
+ ] |
|
| 148 |
+ } |
|
| 149 |
+ } |
|
| 150 |
+ @agent = Agents::HumanTaskAgent.new(:name => "somename", :options => valid_params) |
|
| 151 |
+ @agent.user = users(:jane) |
|
| 152 |
+ LiquidMigrator.convert_all_agent_options(@agent) |
|
| 153 |
+ @agent.reload.options['hit']['description'].should == "Please rate the sentiment of this message: '{{message}}'"
|
|
| 154 |
+ end |
|
| 102 | 155 |
end |
| 103 | 156 |
end |
@@ -1,6 +1,9 @@ |
||
| 1 | 1 |
require 'spec_helper' |
| 2 |
+require 'models/concerns/liquid_interpolatable' |
|
| 2 | 3 |
|
| 3 | 4 |
describe Agents::HumanTaskAgent do |
| 5 |
+ it_behaves_like LiquidInterpolatable |
|
| 6 |
+ |
|
| 4 | 7 |
before do |
| 5 | 8 |
@checker = Agents::HumanTaskAgent.new(:name => "my human task agent") |
| 6 | 9 |
@checker.options = @checker.default_options |
@@ -116,19 +119,19 @@ describe Agents::HumanTaskAgent do |
||
| 116 | 119 |
@checker.options['poll_options'] = { 'title' => "Take a poll about jokes",
|
| 117 | 120 |
'instructions' => "Rank these by how funny they are", |
| 118 | 121 |
'assignments' => 3, |
| 119 |
- 'row_template' => "<$.joke>" } |
|
| 122 |
+ 'row_template' => "{{joke}}" }
|
|
| 120 | 123 |
@checker.should be_valid |
| 121 | 124 |
@checker.options['poll_options'] = { 'instructions' => "Rank these by how funny they are",
|
| 122 | 125 |
'assignments' => 3, |
| 123 |
- 'row_template' => "<$.joke>" } |
|
| 126 |
+ 'row_template' => "{{joke}}" }
|
|
| 124 | 127 |
@checker.should_not be_valid |
| 125 | 128 |
@checker.options['poll_options'] = { 'title' => "Take a poll about jokes",
|
| 126 | 129 |
'assignments' => 3, |
| 127 |
- 'row_template' => "<$.joke>" } |
|
| 130 |
+ 'row_template' => "{{joke}}" }
|
|
| 128 | 131 |
@checker.should_not be_valid |
| 129 | 132 |
@checker.options['poll_options'] = { 'title' => "Take a poll about jokes",
|
| 130 | 133 |
'instructions' => "Rank these by how funny they are", |
| 131 |
- 'row_template' => "<$.joke>" } |
|
| 134 |
+ 'row_template' => "{{joke}}" }
|
|
| 132 | 135 |
@checker.should_not be_valid |
| 133 | 136 |
@checker.options['poll_options'] = { 'title' => "Take a poll about jokes",
|
| 134 | 137 |
'instructions' => "Rank these by how funny they are", |
@@ -207,9 +210,9 @@ describe Agents::HumanTaskAgent do |
||
| 207 | 210 |
|
| 208 | 211 |
describe "creating hits" do |
| 209 | 212 |
it "can create HITs based on events, interpolating their values" do |
| 210 |
- @checker.options['hit']['title'] = "Hi <.name>" |
|
| 211 |
- @checker.options['hit']['description'] = "Make something for <.name>" |
|
| 212 |
- @checker.options['hit']['questions'][0]['name'] = "<.name> Question 1" |
|
| 213 |
+ @checker.options['hit']['title'] = "Hi {{name}}"
|
|
| 214 |
+ @checker.options['hit']['description'] = "Make something for {{name}}"
|
|
| 215 |
+ @checker.options['hit']['questions'][0]['name'] = "{{name}} Question 1"
|
|
| 213 | 216 |
|
| 214 | 217 |
question_form = nil |
| 215 | 218 |
hitInterface = OpenStruct.new |
@@ -232,7 +235,7 @@ describe Agents::HumanTaskAgent do |
||
| 232 | 235 |
end |
| 233 | 236 |
|
| 234 | 237 |
it "works without an event too" do |
| 235 |
- @checker.options['hit']['title'] = "Hi <.name>" |
|
| 238 |
+ @checker.options['hit']['title'] = "Hi {{name}}"
|
|
| 236 | 239 |
hitInterface = OpenStruct.new |
| 237 | 240 |
hitInterface.id = 123 |
| 238 | 241 |
mock(hitInterface).question_form(instance_of Agents::HumanTaskAgent::AgentQuestionForm) |
@@ -483,7 +486,7 @@ describe Agents::HumanTaskAgent do |
||
| 483 | 486 |
'title' => "Hi!", |
| 484 | 487 |
'instructions' => "hello!", |
| 485 | 488 |
'assignments' => 2, |
| 486 |
- 'row_template' => "This is <.sentiment>" |
|
| 489 |
+ 'row_template' => "This is {{sentiment}}"
|
|
| 487 | 490 |
} |
| 488 | 491 |
@event.save! |
| 489 | 492 |
mock(RTurk::GetReviewableHITs).create { mock!.hit_ids { %w[JH3132836336DHG JH39AA63836DHG JH39AA63836DH12345] } }
|
@@ -1,6 +1,9 @@ |
||
| 1 | 1 |
require 'spec_helper' |
| 2 |
+require 'models/concerns/liquid_interpolatable' |
|
| 2 | 3 |
|
| 3 | 4 |
describe Agents::PeakDetectorAgent do |
| 5 |
+ it_behaves_like LiquidInterpolatable |
|
| 6 |
+ |
|
| 4 | 7 |
before do |
| 5 | 8 |
@valid_params = {
|
| 6 | 9 |
'name' => "my peak detector agent", |
@@ -1,6 +1,9 @@ |
||
| 1 | 1 |
require 'spec_helper' |
| 2 |
+require 'models/concerns/liquid_interpolatable' |
|
| 2 | 3 |
|
| 3 | 4 |
describe Agents::TriggerAgent do |
| 5 |
+ it_behaves_like LiquidInterpolatable |
|
| 6 |
+ |
|
| 4 | 7 |
before do |
| 5 | 8 |
@valid_params = {
|
| 6 | 9 |
'name' => "my trigger agent", |
@@ -11,7 +14,7 @@ describe Agents::TriggerAgent do |
||
| 11 | 14 |
'value' => "a\\db", |
| 12 | 15 |
'path' => "foo.bar.baz", |
| 13 | 16 |
}], |
| 14 |
- 'message' => "I saw '<foo.bar.baz>' from <name>" |
|
| 17 |
+ 'message' => "I saw '{{foo.bar.baz}}' from {{name}}"
|
|
| 15 | 18 |
} |
| 16 | 19 |
} |
| 17 | 20 |
|
@@ -20,7 +20,7 @@ shared_examples_for LiquidInterpolatable do |
||
| 20 | 20 |
|
| 21 | 21 |
describe "interpolating liquid templates" do |
| 22 | 22 |
it "should work" do |
| 23 |
- @checker.send(:interpolate_options, @checker.options, @event.payload).should == {
|
|
| 23 |
+ @checker.interpolate_options(@checker.options, @event.payload).should == {
|
|
| 24 | 24 |
"normal" => "just some normal text", |
| 25 | 25 |
"variable" => "hello", |
| 26 | 26 |
"text" => "Some test with an embedded hello", |
@@ -28,6 +28,26 @@ shared_examples_for LiquidInterpolatable do |
||
| 28 | 28 |
} |
| 29 | 29 |
end |
| 30 | 30 |
|
| 31 |
+ it "hsould work with arrays", focus: true do |
|
| 32 |
+ @checker.options = {"value" => ["{{variable}}", "Much array", "Hey, {{hello_world}}"]}
|
|
| 33 |
+ @checker.interpolate_options(@checker.options, @event.payload).should == {
|
|
| 34 |
+ "value" => ["hello", "Much array", "Hey, Hello world"] |
|
| 35 |
+ } |
|
| 36 |
+ end |
|
| 37 |
+ |
|
| 38 |
+ it "should work recursively" do |
|
| 39 |
+ @checker.options['hash'] = {'recursive' => "{{variable}}"}
|
|
| 40 |
+ @checker.options['indifferent_hash'] = ActiveSupport::HashWithIndifferentAccess.new({'recursive' => "{{variable}}"})
|
|
| 41 |
+ @checker.interpolate_options(@checker.options, @event.payload).should == {
|
|
| 42 |
+ "normal" => "just some normal text", |
|
| 43 |
+ "variable" => "hello", |
|
| 44 |
+ "text" => "Some test with an embedded hello", |
|
| 45 |
+ "escape" => "This should be Hello+world", |
|
| 46 |
+ "hash" => {'recursive' => 'hello'},
|
|
| 47 |
+ "indifferent_hash" => {'recursive' => 'hello'},
|
|
| 48 |
+ } |
|
| 49 |
+ end |
|
| 50 |
+ |
|
| 31 | 51 |
it "should work for strings" do |
| 32 | 52 |
@checker.send(:interpolate_string, "{{variable}}", @event.payload).should == "hello"
|
| 33 | 53 |
@checker.send(:interpolate_string, "{{variable}} you", @event.payload).should == "hello you"
|